﻿using System;
using System.Collections.Generic;
using System.Text;
using Musicman.DAL;
using Musicman.Common.Entities;
using Musicman.Common;
using System.Runtime.CompilerServices;
using Microsoft.Practices.EnterpriseLibrary.Data.Sql;

namespace Musicman.Business
{
    public class SearchFileManager
    {
        # region singleton definition
        static readonly SearchFileManager instance = new SearchFileManager();

        public static SearchFileManager Instance
        {
            get
            {
                return instance;
            }
        }
        static SearchFileManager()
        {
        }
        # endregion

        #region select 

        public List<SearchFile> LoadSearchJobFiles(string jobname, string searchLocation)
        {
            List<SearchFile> res = null;
            try
            {
                string where = @" 
    INNER JOIN SearchJob on SearchFile.SearchJobID = SearchJob.SearchJobID 
    WHERE SearchJob.Name = @JOBNAME and SearchFile.FilePath like @FILEPATH";
                SelectParameter[] parameters = {
                             new SelectParameter("@JOBNAME", System.Data.DbType.String, jobname),
                             new SelectParameter("@FILEPATH", System.Data.DbType.String, searchLocation + "%")
                                                  };
                
                res = SearchFileDAO.Instance.LoadSearchfiles(where, "", parameters);
            }
            catch (Exception ex)
            {
                LogManager.LogException("Unable to get list of search job files", ex);
            }

            return res;
        }

        public List<SearchFile> LoadSearchJobFiles(long jobID, string searchLocation)
        {
            List<SearchFile> res = null;
            try
            {
                string where = @" WHERE SearchJobID = @JOBID and FilePath like @FILEPATH";
                SelectParameter[] parameters = 
                {
                     new SelectParameter("@JOBID", System.Data.DbType.Int64, jobID),
                     new SelectParameter("@FILEPATH", System.Data.DbType.String, searchLocation + "%")
                };

                res = SearchFileDAO.Instance.LoadSearchfiles(where, "", parameters);
            }
            catch (Exception ex)
            {
                LogManager.LogException("Unable to get list of search job files", ex);
            }
            return res;
        }

        public SearchFile GetSearchFile(long seardhFileID)
        {
            SearchFile res = null;
            string where = " WHERE SearchFile.SearchFileID = @SEARCHFILEID";
            SelectParameter[] parameters = { 
                                               new SelectParameter("@SEARCHFILEID", System.Data.DbType.Int64, seardhFileID)
                                           };
            List<SearchFile> files = LoadSearchFiles(0, where, "", "", parameters);
            if (files != null && files.Count != 0)
            {
                res = files[0];
            }
            return res;
        }

        public List<SearchFile> LoadTopDownwloadesFiles(long jobId, string keyword, int top, long minSize)
        {
            List<SelectParameter> parameters = new List<SelectParameter>();
            StringBuilder where = new StringBuilder(@" INNER JOIN FilesStats ON FilesStats.SearchFileID = SearchFile.SearchFileID
                                                WHERE SearchFile.SearchJobID = @JOBID");
            parameters.Add(new SelectParameter("@JOBID", System.Data.DbType.Int64, jobId));
            if (minSize != 0)
            {
                where.Append(" AND SearchFile.Length > @LENGTH");
                parameters.Add(new SelectParameter("@LENGTH", System.Data.DbType.Int64, minSize));
            }
            where.Append(ProcessSearchKeywords(keyword, parameters));
            string orderby = " ORDER BY FilesStats.TotalDownloads DESC";
            return LoadSearchFiles(top, where.ToString(), "", orderby, parameters);
        }

        public List<SearchFile> LoadTopRatedFiles(long jobId, string keyword, int top, long minSize)
        {
            List<SelectParameter> parameters = new List<SelectParameter>();
            StringBuilder where = new StringBuilder(@" INNER JOIN FilesStats ON FilesStats.SearchFileID = SearchFile.SearchFileID
                                                WHERE SearchFile.SearchJobID = @JOBID");
            parameters.Add(new SelectParameter("@JOBID", System.Data.DbType.Int64, jobId));
            if (minSize != 0)
            {
                where.Append(" AND SearchFile.Length > @LENGTH");
                parameters.Add(new SelectParameter("@LENGTH", System.Data.DbType.Int64, minSize));
            }
            where.Append(ProcessSearchKeywords(keyword, parameters));
            string orderby = " ORDER BY FilesStats.Rating DESC";
            return LoadSearchFiles(top, where.ToString(), "", orderby, parameters);
        }

        public List<SearchFile> LoadLatestFiles(long jobId, string keyword, int top, long minSize)
        {
            List<SelectParameter> parameters = new List<SelectParameter>();
            StringBuilder where = new StringBuilder(@"WHERE SearchFile.SearchJobID = @JOBID AND SearchFile.PresentSequence = -1");
            parameters.Add(new SelectParameter("@JOBID", System.Data.DbType.Int64, jobId));
            if (minSize != 0)
            {
                where.Append(" AND SearchFile.Length > @LENGTH");
                parameters.Add(new SelectParameter("@LENGTH", System.Data.DbType.Int64, minSize));
            }
            where.Append(ProcessSearchKeywords(keyword, parameters));
            return LoadSearchFiles(top, where.ToString(), "", "", parameters);
        }

        public List<SearchFile> LoadRandomFiles(long jobId, string keyword, int top, long minSize)
        {
            List<SelectParameter> parameters = new List<SelectParameter>();
            StringBuilder where = new StringBuilder(@"WHERE SearchFile.SearchJobID = @JOBID");
            parameters.Add(new SelectParameter("@JOBID", System.Data.DbType.Int64, jobId));
            if (minSize != 0)
            {
                where.Append(" AND SearchFile.Length > @LENGTH");
                parameters.Add(new SelectParameter("@LENGTH", System.Data.DbType.Int64, minSize));
            }
            where.Append(ProcessSearchKeywords(keyword, parameters));
            return LoadSearchFiles(top, where.ToString(), "", " ORDER BY NEWID()", parameters);
        }

        public List<SearchFile> LoadSearchFiles(long jobId, string keyword, int top, long minSize)
        {
            List<SelectParameter> parameters = new List<SelectParameter>();
            StringBuilder where = new StringBuilder(@"WHERE SearchFile.SearchJobID = @JOBID ");
            parameters.Add(new SelectParameter("@JOBID", System.Data.DbType.Int64, jobId));
            if (minSize != 0)
            {
                where.Append(" AND SearchFile.Length > @LENGTH");
                parameters.Add(new SelectParameter("@LENGTH", System.Data.DbType.Int64, minSize));
            }
            where.Append(ProcessSearchKeywords(keyword, parameters));
            return LoadSearchFiles(top, where.ToString(), "", "", parameters);
        }

        public List<SearchFile> LoadSearchFiles(int top, string where, string additional, string orderby, IEnumerable<SelectParameter> parameters)
        {
            List<SearchFile> res = null;
            try
            {
                res = SearchFileDAO.Instance.LoadSearchfiles(top, where, additional, orderby, parameters);
            }
            catch (Exception ex)
            {
                LogManager.LogException("Unable to get list of search job files", ex);
            }
            return res;
        }

        public List<SearchFile> LoadPendingDownloads(long userID)
        {
            List<SelectParameter> parameters = new List<SelectParameter>();
            string where = @"  INNER JOIN UserDownloads ON SearchFile.SearchFileID =  UserDownloads.SearchFielID
WHERE UserDownloads.UserID = @PERSONID";
            parameters.Add(new SelectParameter("@PERSONID", System.Data.DbType.Int64, userID));
            return SearchFileDAO.Instance.LoadSearchfiles(where, "", parameters);
        }

        public string ProcessSearchKeywords(string keyword, List<SelectParameter> parameters)
        {
            StringBuilder where = new StringBuilder();
            keyword = keyword.Replace("'", "''");
            int pCount = 0;
            while (keyword.Contains("\""))
            {
                int index1 = keyword.IndexOf('"');
                int index2 = keyword.IndexOf('"', index1 + 1);
                string part = "";
                if (index2 == -1)
                {
                    part = keyword.Replace("\"", "");
                    keyword = "";
                }
                else
                {
                    part = keyword.Substring(index1 + 1, index2 - index1 - 1);
                    keyword = keyword.Substring(0, (index1 == 0) ? 0 : index1 - 1) + keyword.Substring(index2 + 1);
                }
                pCount++;
                where.AppendFormat(" AND (SearchFile.FilePath like @KEYWORD{0} or SearchFile.Name like @KEYWORD{0}) ", pCount);
                parameters.Add(new SelectParameter(
                                    String.Format("@KEYWORD{0}", pCount),
                                    System.Data.DbType.String,
                                    String.Format("%{0}%", part)));

            }
            string[] words = keyword.Split(' ');
            for (int i = 0; i < words.Length; i++)
            {
                string word = words[i];
                pCount++;
                where.AppendFormat(" AND (SearchFile.FilePath like @KEYWORD{0} or SearchFile.Name like @KEYWORD{0}) ", pCount);
                parameters.Add(new SelectParameter(
                    String.Format("@KEYWORD{0}", pCount),
                    System.Data.DbType.String,
                    String.Format("%{0}%", word)));
            }
            return where.ToString();
        }

        public FileStats LoadFileStatistics(long seardhFileID)
        {
            FileStats res = null;
            try
            {
                res = SearchFileDAO.Instance.GetFileStats(seardhFileID);
            }
            catch (Exception ex)
            {
                LogManager.LogException("Unable to load search file stats files", ex);
            }
            return res;
        }

        public List<HistoryFile> LoadUserHistory(long personID)
        {
            List<HistoryFile> res = null;
            try
            {
                string where = @" WHERE PersonID = @PERSONID";
                string orderby = "ORDER BY DateDownloaded DESC";
                SelectParameter[] parameters = 
                {
                     new SelectParameter("@PERSONID", System.Data.DbType.Int64, personID),
                };

                res = HistoryFileDAO.Instance.LoadSearchfiles(where, orderby, parameters);
            }
            catch (Exception ex)
            {
                LogManager.LogException("Unable to get list of user history files", ex);
            }
            return res;
        }
        #endregion

        #region insert 
        public bool AddToPendingDonwloads(long personID, List<long> files)
        {
            bool res = false;
            try
            {
                SearchFileDAO.Instance.AddToPendingDownloads(personID, files);
                res = true;
            }
            catch (Exception ex)
            {
                LogManager.LogException("Unable to add to pending downloads", ex);
            }
            return res;
        }

        #endregion

        #region update

        public bool SetVisited(long searchJobId, bool visited)
        {
            bool res = true;
            try
            {
                SearchFileDAO.Instance.SetVisited(searchJobId, visited);
            }
            catch (Exception ex)
            {
                res = false;
                LogManager.LogException("Unable to clear hanging files", ex);
            }
            return res;
        }

        public int IncreaseAndDeleteNonVisitedFiles(long searchJobId, int deleteAfter)
        {
            int res = 0;
            try
            {
                SqlDatabase db = SearchFileDAO.Instance.GetDefaultDatabase();
                SearchFileDAO.Instance.IncreasePresentSequence(searchJobId, db);
                res = SearchFileDAO.Instance.DeleteIdleFiles(searchJobId, deleteAfter, db);
            }
            catch (Exception ex)
            {
                res = -1;
                LogManager.LogException("Unable to advance and delete", ex);
            }
            return res;
        }

        public bool SaveSearchResults(List<SearchFile> insertList, List<SearchFile> updateList, List<SearchFile> deleteList)
        {
            bool res = true;
            try
            {
                SqlDatabase db = SearchFileDAO.Instance.GetDefaultDatabase();
                SearchFileDAO.Instance.InsertSearchFileList(insertList, db);
                SearchFileDAO.Instance.UpdateSearchFileList(updateList, db);
                SearchFileDAO.Instance.DeleteSearchFileList(deleteList, db);
            }
            catch (Exception ex)
            {
                res = false;
                LogManager.LogException("Unable to save search results", ex);
            }
            return res;
        }

        public bool UpdateDownloadStats(long personID, long fileID, long fileLength, string fileName, int count)
        {
            bool res = true;
            try
            {
                res = SearchFileDAO.Instance.UpdateDownloadStats(personID, fileID, fileLength, fileName, count);
            }
            catch (Exception ex)
            {
                res = false;
                LogManager.LogException("Unable to update download stats", ex);
            }
            return res;
        }

        public bool UpdateFileStats(long fileID, int rating)
        {
            bool res = true;
            try
            {
                res = SearchFileDAO.Instance.UpdateFileStats(fileID, rating);
            }
            catch (Exception ex)
            {
                res = false;
                LogManager.LogException("Unable to update download stats", ex);
            }
            return res;
        }

        #endregion 

        #region delete
        public bool RemoveFromPendingDownloads(long userID, List<long> files)
        {
            bool res = false;
            try
            {
                SearchFileDAO.Instance.RemoveFromPendingDownloads(userID, files);
                res = true;
            }
            catch (Exception ex)
            {
                LogManager.LogException("Unable to remove from downloads", ex);
            }
            return res;

        }

        #endregion
    }
}
